package br.com.gkarian.mydesk.services.financeiro;

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import br.com.caelum.vraptor.ioc.Component;
import br.com.gkarian.mydesk.dao.financeiro.interfaces.TransacaoDAO;
import br.com.gkarian.mydesk.formatter.ValorFormatter;
import br.com.gkarian.mydesk.model.Usuario;
import br.com.gkarian.mydesk.model.financeiro.ContaBancaria;
import br.com.gkarian.mydesk.model.financeiro.Transacao;
import br.com.gkarian.mydesk.services.financeiro.interfaces.ContaBancariaService;
import br.com.gkarian.mydesk.services.financeiro.interfaces.TransacaoService;
import br.com.gkarian.mydesk.services.interfaces.UsuarioService;

@Component
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public class TransacaoServiceImpl implements TransacaoService {

	private static final Logger LOG = Logger
			.getLogger(TransacaoServiceImpl.class);

	private TransacaoDAO transacaoDao;
	private ContaBancariaService contaBancariaService;
	private UsuarioService usuarioService;
	private ValorFormatter valorFormatter;

	public TransacaoServiceImpl(TransacaoDAO transacaoDao,
			ContaBancariaService contaBancariaService,
			UsuarioService usuarioService) {
		this.transacaoDao = transacaoDao;
		this.contaBancariaService = contaBancariaService;
		this.usuarioService = usuarioService;
		this.valorFormatter = new ValorFormatter();
	}

	@Override
	public void cadastrarTransacao(Transacao transacao, Usuario usuario)
			throws Exception {
		// TODO: recuperar conta bancaria, verificar entrada/saida e calcular no
		// saldo

		LOG.info("Usuario de ID [" + usuario.getId()
				+ "] cadastrando transacao = " + transacao);

		transacao.setUsuario(usuario);
		transacao
				.setValor(valorFormatter.removerPontuacao(transacao.getValor()));

		Integer idContaBancaria = transacao.getContaBancaria().getId();

		List<ContaBancaria> listContasBancarias = usuarioService
				.carregarComListContaBancaria(usuario).getListContasBancarias();
		for (ContaBancaria contaBancaria : listContasBancarias) {
			if (contaBancaria.getId() == idContaBancaria) {

				long saldoAtual = Long.parseLong(contaBancaria.getSaldo());
				long valorTransacao = Long.parseLong(transacao.getValor());

				if (transacao.isEntrada()) {
					saldoAtual += valorTransacao;
				} else {
					saldoAtual -= valorTransacao;
				}

				StringBuilder log = new StringBuilder();
				log.append("Transacao com valor de ")
						.append(transacao.getValor())
						.append(" será contabilizado a ContaBancaria de ID [")
						.append(idContaBancaria).append("]")
						.append(" com saldo atual de ")
						.append(contaBancaria.getSaldo())
						.append(" resultando em ").append(saldoAtual);
				LOG.info(log.toString());

				contaBancaria.setSaldo(String.valueOf(saldoAtual));

				contaBancariaService.atualizarContaBancaria(contaBancaria);

				break;
			}
		}

		transacaoDao.salvar(transacao);

		LOG.info("Transacao cadastrada com sucesso na Conta Bancária de ID ["
				+ idContaBancaria + "]");
	}

	@Override
	public Transacao carregarTransacao(Integer id) throws Exception {
		LOG.info("Carregando transacao de ID [" + id + "]");
		Transacao transacao = transacaoDao.carregar(id);
		LOG.info("Transacao de ID [" + id + "] carregada");
		return transacao;
	}

	@Override
	public void atualizarTransacao(Transacao transacao, Usuario usuario)
			throws Exception {

		LOG.info("Atualizando transacao de ID [" + transacao.getId()
				+ "] pertencente ao Usuario de ID [" + usuario.getId() + "]");

		Transacao transacaoAntiga = transacaoDao.carregar(transacao.getId());

		List<ContaBancaria> listContasBancarias = usuarioService
				.carregarComListContaBancaria(usuario).getListContasBancarias();
		for (ContaBancaria contaBancaria : listContasBancarias) {
			if (contaBancaria.getId() == transacaoAntiga.getContaBancaria()
					.getId()) {

				long saldoAtual = Long.parseLong(contaBancaria.getSaldo());
				long valorTransacaoAntiga = Long.parseLong(transacaoAntiga
						.getValor());

				if (transacaoAntiga.isEntrada()) {
					saldoAtual -= valorTransacaoAntiga;
				} else {
					saldoAtual += valorTransacaoAntiga;
				}

				contaBancaria.setSaldo(String.valueOf(saldoAtual));

				contaBancariaService.atualizarContaBancaria(contaBancaria);

				break;
			}
		}

		transacao.setUsuario(usuario);
		transacao
				.setValor(valorFormatter.removerPontuacao(transacao.getValor()));

		// realizar operação conforme nova atualizacao
		for (ContaBancaria contaBancaria : listContasBancarias) {
			if (contaBancaria.getId() == transacao.getContaBancaria().getId()) {

				long saldoAtual = Long.parseLong(contaBancaria.getSaldo());
				long valorTransacao = Long.parseLong(transacao.getValor());

				if (transacao.isEntrada()) {
					saldoAtual += valorTransacao;
				} else {
					saldoAtual -= valorTransacao;
				}

				contaBancaria.setSaldo(String.valueOf(saldoAtual));

				contaBancariaService.atualizarContaBancaria(contaBancaria);

				break;
			}
		}

		transacaoDao.atualizar(transacao);

		LOG.info("Transacao de ID [" + transacao.getId()
				+ "] atualizada com sucesso");
	}

	@Override
	public List<Transacao> listarTransacoesPorUsuario(Usuario usuario)
			throws Exception {
		LOG.info("Listando transacoes do usuário de ID [" + usuario.getId()
				+ "]");
		List<Transacao> listTransacao = usuarioService
				.carregarParaListarTransacoes(usuario).getListTransacao();
		LOG.info("Recuperado " + listTransacao.size()
				+ " transacoes do usuário de ID [" + usuario.getId() + "]");
		return listTransacao;
	}

	@Override
	public void removerTransacao(Transacao transacao, Usuario usuario)
			throws Exception {

		LOG.info("Removendo Transacao de ID [" + transacao.getId()
				+ "] do Usuario [" + usuario.getId() + "]");

		// TODO: Se for enviado um codigo de conta bancaria invalida, a
		// transacao será removida de qualquer jeito, ocasionando diferença no
		// saldo da conta. Corrigir bug.

		List<ContaBancaria> listContasBancarias = usuarioService
				.carregarComListContaBancaria(usuario).getListContasBancarias();
		for (ContaBancaria contaBancaria : listContasBancarias) {
			if (contaBancaria.getId() == transacao.getContaBancaria().getId()) {

				long saldoAtual = Long.parseLong(contaBancaria.getSaldo());
				long valorTransacao = Long.parseLong(transacao.getValor());

				if (transacao.isEntrada()) {
					saldoAtual -= valorTransacao;
				} else {
					saldoAtual += valorTransacao;
				}

				contaBancaria.setSaldo(String.valueOf(saldoAtual));

				contaBancariaService.atualizarContaBancaria(contaBancaria);

				break;
			}
		}

		transacaoDao.remover(transacao);

		LOG.info("Transacao de ID [" + transacao.getId()
				+ "] removida com sucesso do usuario de ID [" + usuario.getId()
				+ "]");
	}

}
